/**
 *  Github Resource:
 *      - https://github.com/xtensor-stack/xtensor
 *  Depend:
 *      1. https://www.jianshu.com/p/708c1968de52, xtl
 *  Doc:
 *      - https://xtensor.readthedocs.io/en/latest/numpy.html
 *      - https://stackoverflow.com/questions/62829519/converting-xtensor-xarray-to-opencv-mat-back-and-forth-in-cpp
 *      - https://xtensor.readthedocs.io/en/latest/api/xadapt.html#_CPPv4I_11layout_type0_NSt6size_tE0EN2xt5adaptEDaRA1N_1TRK2SC11layout_type
 *
 * time record:
    double start, end;
    double elapsed;
    start = (double) clock();
    end = (double )clock();
    elapsed = (end - start) / CLOCKS_PER_SEC / 10;  // bug
    qDebug() << "Time cost: " << elapsed << "s";
 */
#include "iostream"
#include <opencv2/opencv.hpp>
#include "xtensor.hpp"
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xview.hpp"

cv::Mat preprocessSampleInput(){
    std::string sampleImage = "../../../resource/raw_resize/1.jpg";
    cv::Mat mat = cv::imread(sampleImage);
    cv::resize(mat, mat, cv::Size(20, 20));

    mat.convertTo(mat, CV_32F);
    cv::Scalar matMean; cv::Mat matStd;
    cv::meanStdDev(mat, matMean, matStd);
    matStd += 1e-8;
    double *stdPtr = matStd.ptr<double>();
    cv::Scalar stdScalar(*(stdPtr + 0), *(stdPtr + 1), *(stdPtr + 2));

    cv::subtract(mat, matMean, mat);
    mat /= stdScalar;

    return cv::dnn::blobFromImage(mat);
    return mat;
}

xt::xarray<float> torchStyleSoftmaxImpl(xt::xarray<float> &x){
    xt::xarray<float> e_x = xt::exp(x - xt::amax(x, 1));
    return e_x / xt::sum(e_x, 1);
}

xt::xarray<float> numpyStyleFlip(xt::xarray<float> &x, std::vector<int> axis){
    bool first = true;
    xt::xarray<float> temp;
    for(int &each:axis) {
        if(first) temp = xt::flip(x, each);
        else temp = xt::flip(temp, each);
        first = false;
    }
    return temp;
}


int main(int argc, char *argv[])
{
    xt::xarray<float> arr({1, 2, 3, 4, 5, 6, 7, 8});
    arr.reshape({2, 2, 2});

    cv::Mat sampleImage = preprocessSampleInput();
    xt::xarray<float> arrayMat = xt::adapt((float *)sampleImage.data, 1 * 3 * 20 * 20, xt::no_ownership(), std::vector<std::size_t>{1, 3, 20, 20});
    std::cout << "ori mat" << std::endl;
    std::cout << arrayMat;
    std::cout << "flip mat" << std::endl;
    std::cout << numpyStyleFlip(arrayMat, {3, 2});
    std::cout << "softmax mat" << std::endl;
    std::cout << torchStyleSoftmaxImpl(arrayMat);
}
